package xyz.glinet.th_credentials_manager
import android.util.Log
import com.google.android.gms.threadnetwork.ThreadBorderAgent
import com.google.android.gms.threadnetwork.ThreadNetwork
import com.google.android.gms.threadnetwork.ThreadNetworkCredentials
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBinding
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.IntentSenderRequest
import androidx.activity.result.contract.ActivityResultContracts

import androidx.activity.result.launch
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityOptionsCompat



annotation class IsPreferredCredentialsResult {
  companion object {
    const val PREFERRED_CREDENTIALS_NOT_FOUND = -1
    const val PREFERRED_CREDENTIALS_NOT_MATCHED = 0
    const val PREFERRED_CREDENTIALS_MATCHED = 1
  }
}
fun String.dsToByteArray(): ByteArray {
  return chunked(2).map { it.toInt(16).toByte() }.toByteArray()
}

fun ByteArray.toHex(): String = joinToString(separator = "") { eachByte -> "%02x".format(eachByte) }
class ThCredentialsManagerPlugin: FlutterPlugin, MethodCallHandler {
  /// The MethodChannel that will the communication between Flutter and native Android
  ///
  /// This local reference serves to register the plugin with the Flutter Engine and unregister it
  /// when the Flutter Engine is detached from the Activity
  private lateinit var channel : MethodChannel

  private lateinit var pluginBinding: FlutterPluginBinding

  private lateinit var preferredCredentialsLauncher: ActivityResultLauncher<IntentSenderRequest>
  private fun isPreferred(activeDataSet: String, result: Result) {

    val threadNetworkCredentials =
      ThreadNetworkCredentials.fromActiveOperationalDataset(activeDataSet.dsToByteArray())
    Log.d(
      "threadNetworkCredentials",
      threadNetworkCredentials.channel.toString() + " - " + threadNetworkCredentials.networkName
    )

    ThreadNetwork.getClient(pluginBinding.applicationContext)
            .isPreferredCredentials(threadNetworkCredentials)
            .addOnSuccessListener { re->
              when (re) {
                IsPreferredCredentialsResult.PREFERRED_CREDENTIALS_NOT_MATCHED ->
                  Log.d("isPreferredCredentials", "Credentials not matched.")
                IsPreferredCredentialsResult.PREFERRED_CREDENTIALS_MATCHED ->
                  Log.d("isPreferredCredentials", "Credentials matched.")
                IsPreferredCredentialsResult.PREFERRED_CREDENTIALS_NOT_FOUND ->
                  Log.d("isPreferredCredentials", "Not found.")
              }
            }
            .addOnFailureListener {
              e: Exception -> Log.d("isPreferredCredentials", "ERROR: [${e}]")
            }
  }
  private fun storeCredentials(borderAgentID: String, activeDataSet: String, result: Result) {

    Log.d("debug", borderAgentID)
    val threadBorderAgent = ThreadBorderAgent.newBuilder(borderAgentID.dsToByteArray()).build()
    val threadCredentials = ThreadNetworkCredentials.fromActiveOperationalDataset(activeDataSet.dsToByteArray())
    Log.d("debug", "border router id:" + threadBorderAgent.id)

    ThreadNetwork.getClient(pluginBinding.applicationContext)
            .addCredentials(threadBorderAgent, threadCredentials)
            .addOnSuccessListener {
              Log.d("debug", "Credentials added.")
            }
            .addOnFailureListener {
              e: Exception -> Log.d("debug", "ERROR: [${e}]")
            }
  }
  private fun deleteCredentialsBy(borderAgentID: String, result: Result) {

    val threadBorderAgent = ThreadBorderAgent.newBuilder(borderAgentID.dsToByteArray()).build()
    Log.d("debug", "border router id:" + threadBorderAgent.id)

    ThreadNetwork.getClient(pluginBinding.applicationContext)
            .removeCredentials(threadBorderAgent)
            .addOnSuccessListener {
              Log.d("debug", "Credentials removed.")
            }
            .addOnFailureListener {
              e: Exception -> Log.d("debug", "ERROR: [${e}]")
            }
  }
  private fun resultData(success: Boolean = true,msg:String = "success",data:Any): Map<String, Any> {
    return  mapOf("success" to success,"msg" to  msg, "data" to  data);
  }

  private fun getAllCredentials(re: Result) {
    preferredCredentialsLauncher =
      registerForActivityResult(
        ActivityResultContracts.StartIntentSenderForResult()
      ) { result: ActivityResult ->
        if (result.resultCode == RESULT_OK) {
          val threadNetworkCredentials = ThreadNetworkCredentials.fromIntentSenderResultData(result.data!!)

          Log.d("debug", threadNetworkCredentials.networkName)
          Log.d("debug", threadNetworkCredentials.networkKey.toHex())
          Log.d("debug", threadNetworkCredentials.pskc.toHex())
          Log.d("debug", threadNetworkCredentials.panId.toString())
          Log.d("debug", threadNetworkCredentials.extendedPanId.toHex())
          Log.d("debug", threadNetworkCredentials.activeOperationalDataset.toHex())
        } else {
          Log.d("debug", "User denied request.")
        }
      }
  }





  override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
    channel = MethodChannel(flutterPluginBinding.binaryMessenger, "th_credentials_manager")
    channel.setMethodCallHandler(this)
    pluginBinding = flutterPluginBinding
  }

  override fun onMethodCall(call: MethodCall, result: Result) {
    when (call.method){
      "getPlatformVersion" -> result.success("Android ${android.os.Build.VERSION.RELEASE}")
      "getAllCredentials" -> {
        result.success("Android ${android.os.Build.VERSION.RELEASE}")
      }
      "deleteCredentialsBy" -> {
        deleteCredentialsBy(call.arguments as String,result)
      }
      "storeCredentials" -> {
        val arguments = call.arguments as Map<*,*>
        val agentID = arguments["borderAgentID"] as String
        val dataSet = arguments["activeDataSet"] as String
        storeCredentials(agentID,dataSet,result)
      }
      "isPreferred" -> {
        isPreferred(call.arguments as String,result)
      }
      else -> result.notImplemented()
    }
  }

  override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
    channel.setMethodCallHandler(null)
  }
}
